2 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 Change History (most recent first):
25 $Log: Mac\040OS\040Test\040Responder.c,v $
26 Revision 1.24 2004/12/16 20:49:34 cheshire
27 <rdar://problem/3324626> Cache memory management improvements
29 Revision 1.23 2004/09/17 01:08:50 cheshire
30 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
31 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
32 declared in that file are ONLY appropriate to single-address-space embedded applications.
33 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
35 Revision 1.22 2004/08/13 23:25:01 cheshire
36 Now that we do both uDNS and mDNS, global replace "m->hostname" with
37 "m->MulticastHostname" for clarity
39 Revision 1.21 2004/03/12 21:30:25 cheshire
40 Build a System-Context Shared Library from mDNSCore, for the benefit of developers
41 like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
43 Revision 1.20 2004/02/09 23:23:32 cheshire
44 Advertise "IL 2\4th Floor.apple.com." as another test "browse domain"
46 Revision 1.19 2004/01/24 23:55:15 cheshire
47 Change to use mDNSOpaque16fromIntVal/mDNSVal16 instead of shifting and masking
49 Revision 1.18 2003/11/14 21:27:08 cheshire
50 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
51 Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
53 Revision 1.17 2003/08/14 02:19:54 cheshire
54 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
56 Revision 1.16 2003/08/12 19:56:24 cheshire
61 #include <stdio.h> // For printf()
62 #include <string.h> // For strlen() etc.
64 #include <Events.h> // For WaitNextEvent()
65 #include <SIOUX.h> // For SIOUXHandleOneEvent()
67 #include "mDNSEmbeddedAPI.h" // Defines the interface to the client layer above
69 #include "mDNSMacOS9.h" // Defines the specific types needed to run mDNS on this platform
71 // These don't have to be globals, but their memory does need to remain valid for as
72 // long as the search is going on. They are declared as globals here for simplicity.
74 static mDNS_PlatformSupport p
;
75 static ServiceRecordSet p1
, p2
, afp
, http
, njp
;
76 static AuthRecord browsedomain1
, browsedomain2
;
78 // This sample code just calls mDNS_RenameAndReregisterService to automatically pick a new
79 // unique name for the service. For a device such as a printer, this may be appropriate.
80 // For a device with a user interface, and a screen, and a keyboard, the appropriate
81 // response may be to prompt the user and ask them to choose a new name for the service.
82 mDNSlocal
void Callback(mDNS
*const m
, ServiceRecordSet
*const sr
, mStatus result
)
86 case mStatus_NoError
: debugf("Callback: %##s Name Registered", sr
->RR_SRV
.resrec
.name
->c
); break;
87 case mStatus_NameConflict
: debugf("Callback: %##s Name Conflict", sr
->RR_SRV
.resrec
.name
->c
); break;
88 case mStatus_MemFree
: debugf("Callback: %##s Memory Free", sr
->RR_SRV
.resrec
.name
->c
); break;
89 default: debugf("Callback: %##s Unknown Result %d", sr
->RR_SRV
.resrec
.name
->c
, result
); break;
92 if (result
== mStatus_NameConflict
) mDNS_RenameAndReregisterService(m
, sr
, mDNSNULL
);
95 // RegisterService() is a simple wrapper function which takes C string
96 // parameters, converts them to domainname parameters, and calls mDNS_RegisterService()
97 mDNSlocal
void RegisterService(mDNS
*m
, ServiceRecordSet
*recordset
,
98 UInt16 PortAsNumber
, const char txtinfo
[],
99 const domainlabel
*const n
, const char type
[], const char domain
[])
103 char buffer
[MAX_ESCAPED_DOMAIN_NAME
];
104 UInt8 txtbuffer
[512];
106 MakeDomainNameFromDNSNameString(&t
, type
);
107 MakeDomainNameFromDNSNameString(&d
, domain
);
111 strncpy((char*)txtbuffer
+1, txtinfo
, sizeof(txtbuffer
)-1);
112 txtbuffer
[0] = (UInt8
)strlen(txtinfo
);
117 mDNS_RegisterService(m
, recordset
,
118 n
, &t
, &d
, // Name, type, domain
119 mDNSNULL
, mDNSOpaque16fromIntVal(PortAsNumber
),
120 txtbuffer
, (mDNSu16
)(1+txtbuffer
[0]), // TXT data, length
121 mDNSNULL
, 0, // Subtypes (none)
122 mDNSInterface_Any
, // Interface ID
123 Callback
, mDNSNULL
); // Callback and context
125 ConvertDomainNameToCString(recordset
->RR_SRV
.resrec
.name
, buffer
);
126 printf("Made Service Records for %s\n", buffer
);
129 // RegisterFakeServiceForTesting() simulates the effect of services being registered on
130 // dynamically-allocated port numbers. No real service exists on that port -- this is just for testing.
131 mDNSlocal
void RegisterFakeServiceForTesting(mDNS
*m
, ServiceRecordSet
*recordset
, const char txtinfo
[],
132 const char name
[], const char type
[], const char domain
[])
134 static UInt16 NextPort
= 0xF000;
136 MakeDomainLabelFromLiteralString(&n
, name
);
137 RegisterService(m
, recordset
, NextPort
++, txtinfo
, &n
, type
, domain
);
140 // CreateProxyRegistrationForRealService() checks to see if the given port is currently
141 // in use, and if so, advertises the specified service as present on that port.
142 // This is useful for advertising existing real services (Personal Web Sharing, Personal
143 // File Sharing, etc.) that currently don't register with mDNS Service Discovery themselves.
144 mDNSlocal OSStatus
CreateProxyRegistrationForRealService(mDNS
*m
, UInt16 PortAsNumber
, const char txtinfo
[],
145 const char *servicetype
, ServiceRecordSet
*recordset
)
150 TEndpointInfo endpointinfo
;
151 EndpointRef ep
= OTOpenEndpoint(OTCreateConfiguration(kTCPName
), 0, &endpointinfo
, &err
);
152 if (!ep
|| err
) { printf("OTOpenEndpoint (CreateProxyRegistrationForRealService) failed %d", err
); return(err
); }
154 ia
.fAddressType
= AF_INET
;
155 ia
.fPort
= mDNSOpaque16fromIntVal(PortAsNumber
).NotAnInteger
;
157 bindReq
.addr
.maxlen
= sizeof(ia
);
158 bindReq
.addr
.len
= sizeof(ia
);
159 bindReq
.addr
.buf
= (UInt8
*)&ia
;
161 err
= OTBind(ep
, &bindReq
, NULL
);
163 if (err
== kOTBadAddressErr
)
164 RegisterService(m
, recordset
, PortAsNumber
, txtinfo
, &m
->nicelabel
, servicetype
, "local.");
166 debugf("OTBind failed %d", err
);
172 // Done once on startup, and then again every time our address changes
173 mDNSlocal OSStatus
mDNSResponderTestSetup(mDNS
*m
)
175 char buffer
[MAX_ESCAPED_DOMAIN_NAME
];
176 mDNSv4Addr ip
= m
->HostInterfaces
->ip
.ip
.v4
;
178 ConvertDomainNameToCString(&m
->MulticastHostname
, buffer
);
179 printf("Name %s\n", buffer
);
180 printf("IP %d.%d.%d.%d\n", ip
.b
[0], ip
.b
[1], ip
.b
[2], ip
.b
[3]);
183 printf("Registering Service Records\n");
184 // Create example printer discovery records
185 //static ServiceRecordSet p1, p2;
189 RegisterFakeServiceForTesting(m
, &p1
, "path=/index.html", "Web Server One", "_http._tcp.", "local.");
190 RegisterFakeServiceForTesting(m
, &p2
, "path=/path.html", "Web Server Two", "_http._tcp.", "local.");
192 RegisterFakeServiceForTesting(m
, &p1
, "rn=lpq1", "Epson Stylus 900N", "_printer._tcp.", "local.");
193 RegisterFakeServiceForTesting(m
, &p2
, "rn=lpq2", "HP LaserJet", "_printer._tcp.", "local.");
195 RegisterFakeServiceForTesting(m
, &p1
, "rn=lpq3", "My Printer", "_printer._tcp.", "local.");
196 RegisterFakeServiceForTesting(m
, &p2
, "lrn=pq4", "My Other Printer", "_printer._tcp.", "local.");
199 // If AFP Server is running, register a record for it
200 CreateProxyRegistrationForRealService(m
, 548, "", "_afpovertcp._tcp.", &afp
);
202 // If Web Server is running, register a record for it
203 CreateProxyRegistrationForRealService(m
, 80, "", "_http._tcp.", &http
);
205 // And pretend we always have an NJP server running on port 80 too
206 //RegisterService(m, &njp, 80, "NJP/", &m->nicelabel, "_njp._tcp.", "local.");
208 // Advertise that apple.com. is available for browsing
209 mDNS_AdvertiseDomains(m
, &browsedomain1
, mDNS_DomainTypeBrowse
, mDNSInterface_Any
, "apple.com.");
210 mDNS_AdvertiseDomains(m
, &browsedomain2
, mDNS_DomainTypeBrowse
, mDNSInterface_Any
, "IL 2\\4th Floor.apple.com.");
215 // YieldSomeTime() just cooperatively yields some time to other processes running on classic Mac OS
216 mDNSlocal Boolean
YieldSomeTime(UInt32 milliseconds
)
218 extern Boolean SIOUXQuitting
;
220 WaitNextEvent(everyEvent
, &e
, milliseconds
/ 17, NULL
);
221 SIOUXHandleOneEvent(&e
);
222 return(SIOUXQuitting
);
228 Boolean DoneSetup
= false;
230 SIOUXSettings
.asktosaveonclose
= false;
231 SIOUXSettings
.userwindowtitle
= "\pMulticast DNS Responder";
233 printf("Multicast DNS Responder\n\n");
234 printf("This software reports errors using MacsBug breaks,\n");
235 printf("so if you don't have MacsBug installed your Mac may crash.\n\n");
236 printf("******************************************************************************\n");
238 err
= InitOpenTransport();
239 if (err
) { debugf("InitOpenTransport failed %d", err
); return(err
); }
241 err
= mDNS_Init(&m
, &p
, mDNS_Init_NoCache
, mDNS_Init_ZeroCacheSize
,
242 mDNS_Init_AdvertiseLocalAddresses
, mDNS_Init_NoInitCallback
, mDNS_Init_NoInitCallbackContext
);
243 if (err
) return(err
);
245 while (!YieldSomeTime(35))
247 #if MDNS_ONLYSYSTEMTASK
248 // For debugging, use "#define MDNS_ONLYSYSTEMTASK 1" and call mDNSPlatformIdle() periodically.
249 // For shipping code, don't define MDNS_ONLYSYSTEMTASK, and you don't need to call mDNSPlatformIdle()
250 extern void mDNSPlatformIdle(mDNS
*const m
);
251 mDNSPlatformIdle(&m
); // Only needed for debugging version
253 if (m
.mDNSPlatformStatus
== mStatus_NoError
&& !DoneSetup
)
256 printf("\nListening for mDNS queries...\n");
257 mDNSResponderTestSetup(&m
);
261 if (p1
.RR_SRV
.resrec
.RecordType
) mDNS_DeregisterService(&m
, &p1
);
262 if (p2
.RR_SRV
.resrec
.RecordType
) mDNS_DeregisterService(&m
, &p2
);
263 if (afp
.RR_SRV
.resrec
.RecordType
) mDNS_DeregisterService(&m
, &afp
);
264 if (http
.RR_SRV
.resrec
.RecordType
) mDNS_DeregisterService(&m
, &http
);
265 if (njp
.RR_SRV
.resrec
.RecordType
) mDNS_DeregisterService(&m
, &njp
);